﻿#region Header

/*
    This file is part of ndoctor-statistics.

    ndoctor-statistics is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ndoctor-statistics is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ndoctor-statistics.  If not, see <http://www.gnu.org/licenses/>.
*/

#endregion Header

namespace Probel.NDoctor.Statistics.RepositoriesImpl
{
    using System.Collections.Generic;

    using NHibernate;
    using NHibernate.Linq;

    using Probel.NDoctor.Statistics.Domain;
    using Probel.NDoctor.Statistics.FactoriesImpl;
    using Probel.NDoctor.Statistics.Helpers;

    internal class MySqlRepository : ISessionRepository
    {
        #region Fields

        public readonly ISessionFactory sessionFactory;

        #endregion Fields

        #region Constructors

        public MySqlRepository(string server, string username, string password, string database, bool doUpdateDatabase = false, bool doCreateNewDatabase = false)
        {
            var builder = new MySqlSessionFactoryBuilder(server, username, password, database);
            this.sessionFactory = builder.BuildFactory(doUpdateDatabase, doCreateNewDatabase);
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Gets the users.
        /// </summary>
        public IEnumerable<Application> Applications
        {
            get { return this.Session.Query<Application>(); }
        }

        /// <summary>
        /// Gets the durations.
        /// </summary>
        public IEnumerable<SessionDuration> Durations
        {
            get { return this.Session.Query<SessionDuration>(); }
        }

        /// <summary>
        /// Gets or sets the session.
        /// </summary>
        /// <value>
        /// The session.
        /// </value>
        public ISession Session
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the session factory.
        /// </summary>
        public ISessionFactory SessionFactory
        {
            get
            {
                return this.sessionFactory;
            }
        }

        /// <summary>
        /// Gets the statistics.
        /// </summary>
        public IEnumerable<StatisticEntry> Statistics
        {
            get { return this.Session.Query<StatisticEntry>(); }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Clears the database. It'll wipe all the data.
        /// </summary>
        public void Clear()
        {
            var sqlBatch = new string[]
            {
                "DELETE FROM StatisticEntry",
                "DELETE FROM SessionDuration",
                "DELETE FROM Application",
            };

            foreach (var sql in sqlBatch)
            {
                this.Session
                    .CreateSQLQuery(sql)
                    .ExecuteUpdate();
            }
        }

        [NotAutoSession]
        public void Import(IEnumerable<Application> applications, IEnumerable<StatisticEntry> statistics, IEnumerable<SessionDuration> durations)
        {
            applications.ToUtc();
            statistics.ToUtc();
            durations.ToUtc();

            using (var session = SessionFactory.OpenStatelessSession())
            using (var tx = session.BeginTransaction())
            {
                foreach (var item in applications) { session.Insert(item); }
                foreach (var item in statistics) { session.Insert(item); }
                foreach (var item in durations) { session.Insert(item); }
            }
        }

        /// <summary>
        /// Exports the specified statistics into the remote repository.
        /// </summary>
        /// <param name="statistics">The statistics.</param>
        public void Insert(IEnumerable<StatisticEntry> statistics)
        {
            statistics.ToUtc();
            foreach (var item in statistics)
            {
                this.Session.Save(item);
            }
        }

        /// <summary>
        /// Inserts the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        public void Insert(Application application)
        {
            application.ToUtc();
            this.Session.Save(application);
        }

        /// <summary>
        /// Exports the specified durations into the remote repository.
        /// </summary>
        /// <param name="durations">The durations.</param>
        public void Insert(IEnumerable<SessionDuration> durations)
        {
            durations.ToUtc();
            foreach (var item in durations)
            {
                this.Insert(item);
            }
        }

        /// <summary>
        /// Exports the specified durations into the remote repository.
        /// </summary>
        /// <param name="duration"></param>
        public void Insert(SessionDuration duration)
        {
            duration.ToUtc();
            this.Session.Save(duration);
        }

        /// <summary>
        /// Inserts the specified statistic into the remote repository.
        /// </summary>
        /// <param name="statistic">The statistic.</param>
        public void Insert(StatisticEntry statistic)
        {
            statistic.ToUtc();
            this.Session.Save(statistic);
        }

        /// <summary>
        /// Updates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        public void Update(Application application)
        {
            application.ToUtc();
            this.Session.Update(application);
        }

        #endregion Methods
    }
}